package com.xavier.dong.nio.groupchat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * @author XavierDong
 **/
public class GroupChatServer {

    // 定义属性
    private Selector selector;

    private ServerSocketChannel serverSocketChannel;

    private static final int PORT = 6667;


    // 构造器
    // 初始化公祖
    public GroupChatServer() {

        try {
            // 得到选择器
            this.selector = Selector.open();

            //得到 ServerSocketChannel
            this.serverSocketChannel = ServerSocketChannel.open();

            // 绑定端口
            this.serverSocketChannel.socket().bind(new InetSocketAddress(PORT));

            // 设置 非阻塞模式
            this.serverSocketChannel.configureBlocking(false);

            // 将 ServerSocketChannel 注册到 Selector 上
            this.serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);


        } catch (IOException e) {
            e.printStackTrace();
        }


    }


    // 监听代码
    private void listen() {

        try {

            // 循环 监听
            while (true) {
                int count = this.selector.select();

                if (count > 0) {
                    // 有事件要处理
                    // 遍历 得到的 SelectionKey
                    Iterator<SelectionKey> selectionKeyIterator = this.selector.selectedKeys().iterator();
                    while (selectionKeyIterator.hasNext()) {
                        // 取出 SelectionKey
                        SelectionKey selectionKey = selectionKeyIterator.next();

                        // 监听到 accept
                        if (selectionKey.isAcceptable()) {
                            // 连接事件 并 注册到 Selector 上
                            SocketChannel socketChannel = this.serverSocketChannel.accept();

                            // 设置为 非阻塞的模式
                            socketChannel.configureBlocking(false);

                            socketChannel.register(this.selector, SelectionKey.OP_READ);

                            // 提示
                            System.out.println(socketChannel.getRemoteAddress() + " 上线 ");
                        }

                        if (selectionKey.isReadable()) {  // 通道 发送 read 事件，即通道是可读事件

                            // 处理读（专门写方法）
                            readData(selectionKey);

                        }

                        // 当前的 key 需要删除，防止多线程的时候，重复处理
                        selectionKeyIterator.remove();

                    }

                } else
                    System.out.println("等待........");

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }


    }

    // 读取 客户端消息
    private void readData(SelectionKey selectionKey) {
        // 定义一个 SocketChannel
        SocketChannel socketChannel = null;


        try {
            //取得 关联的 Channel
            socketChannel = ((SocketChannel) selectionKey.channel());

            // 创建Buffer
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            int count = socketChannel.read(byteBuffer);

            // 根据 count的值做处理
            if (count > 0) {
                // 把缓冲区的数据 转成 string
                String str = new String(byteBuffer.array());

                // 输出 该消息
                System.out.println(" from 客户端： " + str);

                // 向其他的客户端转发消息(去掉自己), 专门写一个方法来处理
                sendInfoToOtherClients(str, socketChannel);
            }


        } catch (IOException e) {
            try {
                System.out.println(socketChannel.getRemoteAddress() + " 离线了....");

                // 取消注册
                selectionKey.cancel();

                // 关闭通道
                socketChannel.close();

            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }


    }


    // 转发消息给其他的客户(通道)
    private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException {

        System.out.println("服务器 转发 消息中.");
        // 遍历 所有的注册到 Selector 的 SocketChannel 并 排除 self
        for (SelectionKey selectionKey : selector.keys()) {

            // 通过 key 取出 对应的 SocketChannel
            Channel channel = selectionKey.channel();

            // 排除 自己
            if (channel instanceof SocketChannel && channel != self) {

                // 转型
                SocketChannel dest = (SocketChannel) channel;

                // 将 msg 存储到 Buffer
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());

                // 将 Buffer 数据 写入到 Channel 中
                dest.write(buffer);
            }
        }
    }


    public static void main(String[] args) {

        // 创建一个 服务器 对象
        GroupChatServer groupChatServer = new GroupChatServer();
        groupChatServer.listen();

    }
}
